<?php
/**
 * Created by 老吴.
 * UserMsg:砥砺前行，扬帆起航
 * email:cwwx0128@qq.com
 * QQ:1113249273
 * QQ群:925283872
 * 微信:cww0128
 * Date: 2021/4/15
 * Time: 23:08
 */

namespace app\api\controller;

use addons\third\model\Third;
use app\common\controller\Api;
use Exception;
use fast\Http;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;

class Wechat extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $appid;
    protected $secret;
    protected $loginUrl;


//ACCOUNT ID：225970
//ACCOUNT SID：3e957d9924934a97a7217d099fe1980b
//AUTH TOKEN：e29906698f320c89d75d5511a7cbf027
//
//API 地址：https://openapi.miaodiyun.com/distributor/sendSMS
    public function __construct()
    {

        $this->appid = 'wx53f802d771dd4b59';//get_addon_config("login")['appId'];
        $this->secret = '4c0a0798d75f585c08925433d60b7646';//get_addon_config("login")['secretId'];
        $this->loginUrl = "https://api.weixin.qq.com/sns/jscode2session?" . "appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";//get_addon_config("login")['loginUrl'];
        parent::__construct();
    }

    //https://hongqi-b.maoln.com/api/Auth_login_with_wechat/test

    /**
     * 用户登录
     */
    public function login()
    {
        $code = $this->request->param('code');
        $nickname = $this->request->param('nickname');
        $avatar = $this->request->param('avatar');
        if (!$code) {
            $this->error('code不能为空');
        }

        $openid = self::getOpenid($code);

        Db::startTrans();
        try {
            //第三方
            $model = new Third();
            $info = $model->where(['openid' => $openid])->find();

            if ($info) {
                $userMoel = \app\common\model\User::get($info->user_id);
                $userMoel->save([
                    'nickname' => $nickname,
                    'username' => $nickname,
                    'avatar' => $avatar
                ]);
                $this->auth->direct($info->user_id);
            }else {
                $ret = $this->auth->register($nickname, '123456', '', '', ['avatar' => $avatar]);
                if($ret) {
                    $model->save([
                        'user_id' => $this->auth->id,
                        'platform' => '',
                        'apptype' => 'wxMiniProgram',
                        'openid' => $openid,
                        'openname' => $nickname
                    ]);
                }else {
                    throw new Exception($this->auth->getError());
                }
            }
            Db::commit();
        }catch (ValidateException|PDOException|Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }

        $data = ['userinfo' => $this->auth->getUserinfo()];
        $this->success(__('Sign up successful'), $data);
    }
    /**
     * 登录第一步，获取openid 跟 session_key
     */
    public function code()
    {
        $code = $this->request->param('code');
        if (!$code) {
            $this->error('code不能为空');
        }
        self::getOpenid($code);
    }


    /**
     * @param $code 用来交换获取openid 跟 session_key
     */
    public function getOpenid($code)
    {
        $url = sprintf($this->loginUrl, $this->appid, $this->secret, $code);
        $result = Http::get($url);
        $wxResult = json_decode($result, true);

        if (empty($wxResult)) {
            $this->error('获取sessin_key及openID时异常');
        }
        if (isset($wxResult['errcode']) && $wxResult['errcode'] != 0) {
            $this->error($wxResult['errmsg']);
        }
        $item = [
            'openid' => $wxResult['openid'],
            'session_key' => $wxResult['session_key']
        ];

//        return $wxResult['openid'];
        $this->success('成功', $item);
    }


    /**
     * 用户登录
     */
    public function login_1()
    {
        $encryptedData = $this->request->post('encryptedData');
        $iv = $this->request->post('iv');
        $sessionKey = $this->request->post('sessionKey');
        $openid = $this->request->post('openid');

        if (empty($encryptedData) || empty($iv) || empty($sessionKey) || empty($openid)) {
            $this->error('缺少参数');
        }

        $errCode = self::decryptData($encryptedData, $iv, $data, $sessionKey, $this->appid);
        if ($errCode == 0) {
            $result = json_decode($data, true);

            $userinfo = \app\admin\model\User::where(['openid' => $openid])->find();

//            $ah = new Auth();

            if ($userinfo) {
                $userinfo->nickname = $result['nickName'];
                $userinfo->avatar = $result['avatarUrl'];
                $userinfo->gender = $result['gender'];
                $userinfo->city = $result['city'];
                $userinfo->province = $result['province'];
                $userinfo->country = $result['country'];
                $userinfo->save();
                $this->auth->direct($userinfo['id']);
            } else {
                $user = new \app\admin\model\User();
                $user->data([
                    'nickname' => $result['nickName'],
                    'avatar' => $result['avatarUrl'],
                    'gender' => $result['gender'],
                    'city' => $result['city'],
                    'province' => $result['province'],
                    'country' => $result['country'],
                    'status' => 'normal',
                    'openid' => $openid
                ]);
                $user->save();
                $this->auth->direct($user->id);
            }
            $this->success('登录成功', $this->auth->getUserinfo());
        } else {
            $this->error('登录失败' . $errCode);
        }
    }

    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0，失败返回对应的错误码
     */
    public function decryptData_1($encryptedData, $iv, $sessionKey, $appid)
    {
        if (strlen($sessionKey) != 24) {
            return -41001;
        }
        $aesKey = base64_decode($sessionKey);


        if (strlen($iv) != 24) {
            return -41002;
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

        $dataObj = json_decode($result);
        if ($dataObj == NULL) {
            return -41003;
        }
        if ($dataObj->watermark->appid != $appid) {
            return -41003;
        }

        return $result;
    }

    /**
     * 获取微信小程序session_key
     *
     * @params string $code 加密code
     * @return array
     */
    public function getWxMiniProgramSessionKey()
    {
        $code = $this->request->param('code', '');
        $wechat = new Wechat('wxMiniProgram');
        $decryptSession = $wechat->code($code);
        if (!isset($decryptSession['session_key'])) {
            $this->error('未获取session_key,请重启应用');
        }
        /* $decryptSession 返回信息
         * Array (
            [session_key] => +T6cy02bJ9JZ1qNmxPdIyA==
            [openid] => o5qMj5cHODXencTC3oZOqKslhHMw
            [unionid] => oqN-A6hQFIM-drK14aF8kxt0ajcA
        )*/
        \think\Cache::set($decryptSession['session_key'], $decryptSession, 24 * 3600); // 强制1天过期
        $this->success('获取session_key', $decryptSession);
    }

    /**
     * 微信小程序登录
     *
     * @params string $openid 唯一标识
     * @params string $sessionKey 秘钥
     * @params string $iv 偏移量
     * @params string $encryptedData 加密串
     * @return array
     */
    public function wxMiniProgramLogin()
    {
        $params = $this->request->post();

        // 入参
        extract($params);

        if (empty($iv) || empty($sessionKey) || empty($encryptedData)) {
            $this->error('缺少必要参数!');
        }

        $result = [];
        try {
            $wechat = new \app\common\library\Wechat('wxMiniProgram');
            $decryptSession = \think\Cache::get($sessionKey);
            if (!$decryptSession || !isset($decryptSession['openid'])) {
                $this->error('未获取到登录态,请重试!');
            }

            $decryptUserInfo = $wechat->decryptData($sessionKey, $iv, $encryptedData, $this->appid); // 私密信息客户端传值数据都不可信，需服务端解密用户信息

            /* $decryptUserInfo 解密信息
             * Array (
                [nickName] => 霍文霆
                [gender] => 0
                [language] => zh_CN
                [city] =>
                [province] =>
                [country] =>
                [avatarUrl] => https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKo4aG0dR4xibGA0RFaqwr7NkXtxoSlhK87nuuib0geVYLzMF3UboicfTsYpnBXwiadYhP9A908wJynfQ/132
                [watermark] => Array (
                    [timestamp] => 1650307101
                    [appid] => wxe633132f7b03f458
                )
            )*/

            $decryptUserInfo = array_merge($decryptUserInfo, $decryptSession);
            //组装decryptData
            $decryptData = array_change_key_case($decryptUserInfo, CASE_LOWER); // 将数组中的所有键名修改为小写
            if (empty($decryptData['openid'])) {
                $this->error('code错误,请重试!');
            }

            /* $decryptData 合并解密信息
             * Array (
                [nickname] => 霍文霆
                [gender] => 0
                [language] => zh_CN
                [city] =>
                [province] =>
                [country] =>
                [avatarurl] => https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKo4aG0dR4xibGA0RFaqwr7NkXtxoSlhK87nuuib0geVYLzMF3UboicfTsYpnBXwiadYhP9A908wJynfQ/132
                [watermark] => Array (
                    [timestamp] => 1650310060
                    [appid] => wxe633132f7b03f458
                )
                [session_key] => oOirEkIjeu/5f9FoTmxEKQ==
                [openid] => o5qMj5cHODXencTC3oZOqKslhHMw
                [unionid] => oqN-A6hQFIM-drK14aF8kxt0ajcA
            )*/

            $user = \app\common\model\User::get([
                'platform' => 'wxMiniProgram',
                'openid'   => $decryptData['openid']
            ]);

            if (!empty($user)) {
                if ($user->status != 'normal') {
                    $this->error(__('Account is locked'));
                }

                $user->nickname = base64_decode(base64_encode($decryptData['nickname'])); // 为了解析昵称当中的表情信息
                $user->avatar = $decryptData['avatarurl'];
                $user->save();
                // 直接登陆
                $result = $this->auth->direct($user->id);
            } else {
                // 写入个人数据
                $decryptData['avatarurl'] = $decryptData['avatar'];
                $result = $this->auth->oauthRegister($decryptData, 'wxMiniProgram');
            }
        } catch (\Exception $e) {
            $this->error($e->getMessage());
        }

        if ($result) {
            $this->success('授权登录成功', $this->auth->getUserInfo());
        } else {
            $this->error('授权登录失败了!');
        }
    }

    /**
     * 获取用户手机号
     *
     * @params string $sessionKey 秘钥
     * @params string $iv 偏移量
     * @params string $encryptedData 加密串
     */

    public function decryptData($encryptedData, $iv, $sessionKey, $appid)
    {
        $code = 0;

        if (strlen($sessionKey) != 24) {
            $code = -41001;
        }
        $aesKey = base64_decode($sessionKey);


        if (strlen($iv) != 24) {
            $code =  -41002;
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

        $dataObj = json_decode($result);

        if ($dataObj == NULL) {
            $code = -41003;
        }
//        if ($dataObj->watermark->appid != $appid) {
//            $code =  -41003;
//        }

        return [
            'code' => $code,
            'phoneNumber' => $dataObj->phoneNumber
        ];
    }

    public function getUserMobile()
    {
        $params = $this->request->post();
        // 入参
        extract($params);

        if (empty($iv) || empty($sessionKey) || empty($encryptedData)|| empty($openid)) {
            $this->error('缺少参数!');
        }
        $decryptData = $this->decryptData($encryptedData, $iv, $sessionKey, $this->appid);
        if($decryptData['code'] != 0 || !isset($decryptData['phoneNumber'])) {
            $this->error('获取手机号失败,请重试!');
        }
        try {
//            $wechat = new \app\common\library\Wechat('wxMiniProgram');

            //第三方
            $model = new Third();
            $info = $model->where(['openid' => $openid])->find();
            $nickname = $decryptData['phoneNumber'];
            if ($info) {
                $userMoel = \app\common\model\User::get($info->user_id);
                $userMoel->save([
                    'nickname' => $nickname,
                    'username' =>  $nickname,
                    'mobile' => $nickname
                ]);
                $this->auth->direct($info->user_id);
            }else {
                $ret = $this->auth->register($nickname, '123456', '', $nickname);
                if($ret) {
                    $model->save([
                        'user_id' => $this->auth->id,
                        'platform' => '',
                        'apptype' => 'wxMiniProgram',
                        'openid' => $openid,
                        'openname' => $nickname
                    ]);
                }else {
                    throw new Exception($this->auth->getError());
                }
            }
        } catch (\Exception $e) {
            $this->error($e->getMessage());
        }
        $userinfo = $this->auth->getUserinfo();

        if($userinfo) {
            $data = ['userinfo' => $userinfo];
            $this->success(__('Sign up successful'), $data);
        }else{
            $this->error(__('登录失败，请重新授权'));
        }

    }
}